home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / nrcmd.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  38KB  |  1,656 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5. /* Mods by G1EMM, PA0GRI and WG7J */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <time.h>
  10. #ifdef MSDOS
  11. #include <dos.h>
  12. #endif
  13. #include "config.h"
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "ax25.h"
  17. #include "mailbox.h"
  18. #include "netrom.h"
  19. #include "nr4.h"
  20. #include "timer.h"
  21. #include "iface.h"
  22. #include "pktdrvr.h"
  23. #include "lapb.h"
  24. #include "cmdparse.h"
  25. #include "session.h"
  26. #include "socket.h"
  27. #include "commands.h"
  28. #include "files.h"
  29.  
  30. int Nr_hidden = 1;
  31. unsigned Nr_sorttype = 1;
  32. char Nr4user[AXALEN];
  33.  
  34. char *Nr4states[] = {
  35.     "Disconnected",
  36.     "Conn Pending",
  37.     "Connected",
  38.     "Disc Pending",
  39.     "Listening"
  40. } ;
  41.  
  42. char *Nr4reasons[] = {
  43.     "Normal",
  44.     "By Peer",
  45.     "Timeout",
  46.     "Reset",
  47.     "Refused"
  48. } ;
  49. static int dobcnodes __ARGS((int argc,char *argv[],void *p));
  50. static int dobcpoll __ARGS((int argc,char *argv[],void *p));
  51. static int dointerface __ARGS((int argc,char *argv[],void *p));
  52. static int donfadd __ARGS((int argc,char *argv[],void *p));
  53. static int donfdrop __ARGS((int argc,char *argv[],void *p));
  54. static int donfdump __ARGS((void));
  55. static int donfmode __ARGS((int argc,char *argv[],void *p));
  56. static int donodefilter __ARGS((int argc,char *argv[],void *p));
  57. static int donodetimer __ARGS((int argc,char *argv[],void *p));
  58. extern int donralias __ARGS((int argc,char *argv[],void *p));
  59. static int donracktime __ARGS((int argc,char *argv[],void *p));
  60. static int donrmycall __ARGS((int argc,char *argv[],void *p));
  61. static int donrchoketime __ARGS((int argc,char *argv[],void *p));
  62. static int donrconnect __ARGS((int argc,char *argv[],void *p));
  63. static int donrirtt __ARGS((int argc,char *argv[],void *p));
  64. static int donrkick __ARGS((int argc,char *argv[],void *p));
  65. static int dorouteadd __ARGS((int argc,char *argv[],void *p));
  66. static int doroutedrop __ARGS((int argc,char *argv[],void *p));
  67. static int donrqlimit __ARGS((int argc,char *argv[],void *p));
  68. static int donrreset __ARGS((int argc,char *argv[],void *p));
  69. static int donrretries __ARGS((int argc,char *argv[],void *p));
  70. static int donrroute __ARGS((int argc,char *argv[],void *p));
  71. static int donrstatus __ARGS((int argc,char *argv[],void *p));
  72. static int donrsave __ARGS((int argc,char *argv[],void *p));
  73. static int donrload __ARGS((int argc,char *argv[],void *p));
  74. static int donrttl __ARGS((int argc,char *argv[],void *p));
  75. static int donruser __ARGS((int argc,char *argv[],void *p));
  76. static int donrwindow __ARGS((int argc,char *argv[],void *p));
  77. void doobsotick __ARGS((void));
  78. static int doobsotimer __ARGS((int argc,char *argv[],void *p));
  79. static int dominquality __ARGS((int argc,char *argv[],void *p));
  80. static int donrtype __ARGS((int argc,char *argv[],void *p));
  81. static int donrpromisc __ARGS((int argc,char *argv[],void *p));
  82. static int donrderate __ARGS((int argc,char *argv[],void *p));
  83. static int doroutesort __ARGS((int argc,char *argv[],void *p));
  84. static int donrhidden __ARGS((int argc,char *argv[],void *p));
  85. static void doallinfo __ARGS((void));
  86.  
  87. int donrneighbour __ARGS((int argc,char *argv[],void *p));
  88.  
  89. extern int donr4tdisc __ARGS((int argc,char *argv[],void *p));
  90. extern struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
  91. extern void nrresetlinks(struct nrroute_tab *rp);
  92.  
  93. static struct cmds Nrcmds[] = {
  94.     "acktime",      donracktime,    0, 0,   NULLCHAR,
  95.     "alias",    donralias,  0, 0,   NULLCHAR,
  96.     "bcnodes",  dobcnodes,  0, 2,   "netrom bcnodes <iface>",
  97.     "bcpoll",   dobcpoll,   0, 2,   "netrom bcpoll <iface>",
  98. #ifdef ALLSESSIONS
  99.     "connect",  donrconnect, 1024, 2,   "netrom connect <node>",
  100. #endif
  101.     "call",     donrmycall,   0, 0,   NULLCHAR,
  102.     "choketime",    donrchoketime,  0, 0,   NULLCHAR,
  103.     "derate",       donrderate,     0, 0,   NULLCHAR,
  104.     "hidden",   donrhidden, 0, 0,   NULLCHAR,
  105.     "interface",    dointerface,    0, 0, NULLCHAR,
  106.     "irtt",         donrirtt,       0, 0,   NULLCHAR,
  107.     "kick",         donrkick,       0, 2,   "netrom kick <&nrcb>",
  108.     "load",         donrload,       0, 0,   NULLCHAR,
  109.     "minquality",   dominquality,   0, 0,   NULLCHAR,
  110.     "neighbour",    donrneighbour,  0, 0,   NULLCHAR,
  111.     "nodefilter",   donodefilter,   0, 0,   NULLCHAR,
  112.     "nodetimer",    donodetimer,    0, 0,   NULLCHAR,
  113.     "obsotimer",    doobsotimer,    0, 0,   NULLCHAR,
  114.     "promiscuous",  donrpromisc,    0, 0,   NULLCHAR,
  115.     "qlimit",       donrqlimit,     0, 0,   NULLCHAR,
  116.     "route",    donrroute,  0, 0,   NULLCHAR,
  117.     "reset",        donrreset,      0, 2,   "netrom reset <&nrcb>",
  118.     "retries",      donrretries,    0, 0,   NULLCHAR,
  119.     "status",       donrstatus,     0, 0,   NULLCHAR,
  120.     "save",         donrsave,       0, 0,   NULLCHAR,
  121. #ifdef ALLSESSIONS
  122. #ifdef ALLSERV
  123.     "split",    donrconnect, 1024, 2,   "netrom split <node>",
  124. #endif
  125. #endif
  126.     "timertype",    donrtype,   0, 0,   NULLCHAR,
  127.     "ttl",          donrttl,        0, 0,   NULLCHAR,
  128. #ifdef NR4TDISC
  129.     "tdisc",    donr4tdisc, 0, 0,   NULLCHAR,
  130. #endif
  131.     "user",     donruser,   0, 0,   NULLCHAR,
  132.     "window",       donrwindow,     0, 0,   NULLCHAR,
  133.     NULLCHAR,
  134. } ;
  135.  
  136.  
  137. struct timer Nodetimer ; /* timer for nodes broadcasts */
  138. struct timer Obsotimer ; /* timer for aging routes */
  139.  
  140. /* Command multiplexer */
  141. int
  142. donetrom(argc,argv,p)
  143. int argc ;
  144. char *argv[] ;
  145. void *p;
  146. {
  147.     return subcmd(Nrcmds,argc,argv,p) ;
  148. }
  149.  
  150. static struct cmds Routecmds[] = {
  151.     "add",  dorouteadd,     0, 6,
  152.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  153.     "drop", doroutedrop, 0, 4,
  154.         "netrom route drop <destination> <neighbor> <interface>",
  155.     "info", dorouteinfo, 0, 0,
  156.     "",
  157.     "sort", doroutesort, 0, 1,
  158.         "",
  159.     NULLCHAR,
  160. } ;
  161.  
  162. /* Route command multiplexer */
  163. static int
  164. donrroute(argc, argv,p)
  165. int argc ;
  166. char *argv[] ;
  167. void *p;
  168. {
  169.     if(argc < 2) {
  170.         doroutedump() ;
  171.         return 0 ;
  172.     }
  173.     return subcmd(Routecmds,argc,argv,p) ;
  174. }
  175.  
  176. /* Code to sort Netrom node listing
  177.  * D. Crompton  2/92
  178.  * Dump a list of known netrom routes in
  179.  * sorted order determined by sort
  180.  * flag - default = sort by alias
  181.  */
  182.  
  183. int
  184. doroutedump()
  185. {
  186.     extern unsigned Nr_sorttype;
  187.     register struct nrroute_tab *rp ;
  188.     register int i,j,k, column ;
  189.     char buf[17] ;
  190.     char *cp,*temp ;
  191.     
  192.     column = 1 ;
  193.     
  194.     for(i = 0,j=0 ; i < NRNUMCHAINS ; i++)
  195.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ;j++,rp = rp->next);
  196.     if (j) {
  197.     /* Allocate maximum size */
  198.     temp = mallocw ((unsigned)j*17);
  199.     
  200.     for(i = 0,j=0,k=0 ; i < NRNUMCHAINS ; i++)
  201.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  202.         if(!Nr_hidden && *rp->alias == '#')
  203.             continue;
  204.         if (Nr_sorttype) {
  205.             strcpy(buf,rp->alias) ;
  206.             /* remove trailing spaces */
  207.             if((cp = strchr(buf,' ')) == NULLCHAR)
  208.             cp = &buf[strlen(buf)] ;
  209.             if(cp != buf)   /* don't include colon for null alias */
  210.             *cp++ = ':' ;
  211.             pax25(cp,rp->call) ;
  212.         } else {
  213.             pax25(buf,rp->call);
  214.             cp=&buf[strlen(buf)];
  215.             *cp++=':';
  216.             strcpy(cp,rp->alias);
  217.         }
  218.         sprintf(&temp[k],"%-16.16s",buf);
  219.         k+=17;
  220.         j++;    /* number actually shown */
  221.         }
  222.  
  223.     qsort(temp,(size_t)j,17,(int (*)__FARGS((const void*,const void*))) strcmp);
  224.         
  225.     for (i=0,k=0;i<j;i++,k+=17) {
  226.         tprintf("%-16s  ",&temp[k]) ;
  227.             if(column++ == 4) {
  228.         if(tprintf("\n") == EOF) {
  229.                     free(temp);
  230.                     return 0;
  231.         }
  232.                 column = 1 ;
  233.             }
  234.         }
  235.  
  236.     if(column != 1)
  237.     tputc('\n') ;
  238.     free(temp);
  239.     }
  240.     return 0 ;
  241. }
  242.  
  243. /* netrom Route Dump Sort - ALIAS or CALL first */
  244. static int
  245. doroutesort(argc,argv,p)
  246. int argc ;
  247. char *argv[] ;
  248. void *p ;
  249. {
  250.     extern unsigned Nr_sorttype;
  251.  
  252.     if(argc < 2) {
  253.         tprintf("Netrom Sort by %s\n", Nr_sorttype ? "Alias" : "Call" ) ;
  254.         return 0 ;
  255.     }
  256.     
  257.     switch(argv[1][0]) {
  258.         case 'A':
  259.         case 'a':
  260.             Nr_sorttype = 1 ;
  261.             break ;
  262.         case 'C':
  263.         case 'c':
  264.             Nr_sorttype = 0 ;
  265.             break ;
  266.         default:
  267.             tprintf("usage: netrom sort [alias|call]\n") ;
  268.             return -1 ;
  269.     }
  270.  
  271.     return 0 ;
  272. }
  273.  
  274. /* Print detailed information on  ALL routes  (sorted) */
  275. /*  D. Crompton */
  276. static void
  277. doallinfo()
  278. {
  279.       extern unsigned Nr_sorttype;
  280.       register struct nrroute_tab *rp ;
  281.       register struct nr_bind *bp ;
  282.       register struct nrnbr_tab *np ;
  283.       char neighbor[AXBUF] ;
  284.       char buf[17];
  285.       char *cp,*temp;
  286.       int i,j,k, flow_tmp;
  287.  
  288.       flow_tmp=Current->flowmode;
  289.       Current->flowmode=1;
  290.         
  291.       for (i=0,j=0;i<NRNUMCHAINS;i++)
  292.         for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
  293.            for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,j++); 
  294.            
  295.       if (j) {
  296.  
  297.        temp=mallocw ((unsigned)j*50);
  298.  
  299.        for (i=0,k=0;i<NRNUMCHAINS;i++)
  300.         for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
  301.            for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,k+=50) {
  302.          np = bp->via ;
  303.          if (Nr_sorttype) {
  304.            
  305.            strcpy(buf,rp->alias) ;
  306.            if((cp = strchr(buf,' ')) == NULLCHAR)
  307.                cp = &buf[strlen(buf)] ;
  308.            if(cp != buf) 
  309.                *cp++ = ':' ;
  310.            pax25(cp,rp->call) ;
  311.          
  312.          } else {
  313.            
  314.            pax25(buf,rp->call);
  315.            cp=&buf[strlen(buf)];
  316.            *cp++=':';
  317.            strcpy(cp,rp->alias);
  318.          
  319.          }
  320.  
  321.      sprintf(&temp[k],"%-16s %3d %3d %-8s %-9s %c\n",buf,
  322.              bp->quality,bp->obsocnt,
  323.          np->iface->name,
  324.              pax25(neighbor,np->call),
  325.          (bp->flags & NRB_PERMANENT ? 'P' :
  326.          bp->flags & NRB_RECORDED ? 'R' : 'B'));
  327.             
  328.         }
  329.          qsort(temp,(size_t)j,50,(int (*)__FARGS((const void*,const void*))) strcmp);
  330.  
  331.          for (i=0,k=0;i<j;i++,k+=50)
  332.         if (tprintf("%s",&temp[k])==EOF)
  333.                break;
  334.          free (temp);
  335.          Current->flowmode=flow_tmp;
  336.        }
  337. }
  338.  
  339.     
  340. /* print detailed information on an individual route
  341.  * Shows alias as well - WG7J
  342.  */
  343. int
  344. dorouteinfo(argc,argv,p)
  345. int argc ;
  346. char *argv[] ;
  347. void *p;
  348. {
  349.     char *cp;
  350.     register struct nrroute_tab *rp ;
  351.     register struct nrroute_tab *npp;
  352.     struct nr_bind *bp ;
  353.     struct nrnbr_tab *np ;
  354.     char destbuf[AXBUF];
  355.     char neighbor[AXBUF] ;
  356.     char alias[AXALEN];
  357.     char buf[AXALEN];
  358.     char nb_alias[AXALEN];
  359.     int print_header=1;
  360.     int16 rhash;
  361.  
  362.     if (argc == 1) {
  363.     doallinfo();
  364.     return 0;
  365.     }
  366.  
  367.     putalias(alias,argv[1],0);
  368.     strupr(argv[1]);    /*make sure it's upper case*/
  369.     if((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  370.     /*no such call or node alias*/
  371.     tputs("no such node\n\n");
  372.     return 0;
  373.      }
  374.     /*copy the real alias*/
  375.     strcpy(buf,rp->alias) ;
  376.     if((cp = strchr(buf,' ')) != NULLCHAR)
  377.     *cp = '\0';
  378.  
  379.     for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  380.         np = bp->via ;
  381.     /*now we have to find the alias of the neighbour used
  382.      *so we can print that as well!
  383.      */
  384.     rhash = nrhash(np->call);
  385.     for(npp=Nrroute_tab[rhash];npp!=NULLNRRTAB;npp=npp->next)
  386.         if(addreq(npp->call,np->call))
  387.         break;
  388.     /* found, now remove trailing spaces */
  389.     strcpy(nb_alias,npp->alias) ;
  390.     if((cp = strchr(nb_alias,' ')) != NULLCHAR)
  391.         *cp = '\0';
  392.     if(print_header) {
  393.         print_header = 0;
  394.         tputs("      Node          Neighbour       Port  PQual Obsocnt Type\n");
  395.         tprintf("%6s:%-9s  ",buf,pax25(destbuf,rp->call));
  396.     } else
  397.         tputs("                  ");
  398.     tprintf("%6s:%-9s  %-3s    %3d      %d     %c\n",
  399.          nb_alias,pax25(neighbor,np->call),
  400.          np->iface->name,
  401.          bp->quality,bp->obsocnt,
  402.          bp->flags & NRB_PERMANENT ? 'P' : \
  403.          (bp->flags & NRB_RECORDED ? 'R' : 'B') );
  404.     }
  405.     tputc('\n');
  406.     return 0 ;
  407. }
  408.  
  409. int
  410. donrneighbour(argc,argv,p)
  411. int argc;
  412. char *argv[];
  413. void *p;
  414. {
  415.     int i,printheader=1;
  416.     struct nrnbr_tab *np;
  417.     struct nrroute_tab *rp;
  418.     struct nr_bind *bind;
  419.     int16 rhash;
  420.     int justused;
  421.     char tmp[AXBUF];
  422.     char alias[AXALEN];
  423.     char *cp;
  424.     int quality = 0;
  425.     int obsocnt = 0;
  426.  
  427.     for(i=0;i<NRNUMCHAINS;i++)  /*loop through all chains of neighbours*/
  428.     for(np=Nrnbr_tab[i];np!=NULLNTAB;np=np->next) {
  429.         /* If the interface is hidden, then do not show the route */
  430. /*
  431.         if(np->iface->flags & HIDE_PORT && Curproc->input != Command->input)
  432.         continue;
  433.  */
  434.         if(printheader) {
  435.                 tputs("Routes :\n" \
  436.                       "   Neighbour       Port  PQual Obsocnt Dest\n");
  437.         printheader = 0;
  438.         }
  439.         /* has this one been used recently ? */
  440.         if((secclock() - np->lastsent) < 60)
  441.         justused = 1;
  442.         else
  443.         justused = 0;
  444.  
  445.         /*now we have to find the alias of this neighbour
  446.          *so we can print that as well!
  447.          */
  448.         rhash = nrhash(np->call);
  449.         for(rp=Nrroute_tab[rhash];rp!=NULLNRRTAB;rp=rp->next)
  450.         if(addreq(rp->call,np->call))
  451.             break;
  452.  
  453.         if(rp != NULLNRRTAB) {
  454.         /* found, now remove trailing spaces */
  455.         strcpy(alias,rp->alias) ;
  456.         if((cp = strchr(alias,' ')) != NULLCHAR)
  457.             *cp = '\0';
  458.         /*find the quality for this neighbour*/
  459.         bind = find_best(rp->routes,1);
  460.         quality = bind->quality;
  461.         obsocnt = bind->obsocnt;
  462.         } else {
  463.         strcpy(alias,"##TEMP");
  464.         }
  465.  
  466.         /* print it all out */
  467.             tprintf("%s %6s:%-9s  %-5s %4d     %1d    %3d\n",
  468.                     (justused) ? ">" : " ",
  469.             alias,pax25(tmp,np->call),
  470.             np->iface->name,
  471.             quality,obsocnt,np->refcnt);
  472.     }
  473.     if(!printheader)
  474.     tputc('\n');
  475.     return 0;
  476. }
  477.  
  478. /* define the netrom call,
  479.  * this simply changes the interface linkaddress!
  480.  * but is a little easier to use...
  481.  */
  482. static int
  483. donrmycall(argc,argv,p)
  484. int argc ;
  485. char *argv[] ;
  486. void *p;
  487. {
  488.     int len;
  489.     char tmp[AXBUF];
  490.  
  491.     if(Nr_iface == NULLIF) {
  492.     tputs("Attach netrom interface first\n") ;
  493.     return 1 ;
  494.     }
  495.  
  496.     if(argc < 2) {
  497.     if (Nr_iface->hwaddr == NULLCHAR)
  498.         tputs("not set\n");
  499.     else
  500.         tprintf("%s\n",pax25(tmp,Nr_iface->hwaddr));
  501.     } else {
  502.     if( (len=strlen(argv[1])) > (AXBUF - 1)) {
  503.         tputs("too long\n");
  504.         return 1;
  505.     }
  506.     if(Nr_iface->hwaddr != NULLCHAR)
  507.         free(Nr_iface->hwaddr);
  508.     Nr_iface->hwaddr = mallocw((unsigned)Nr_iface->iftype->hwalen);
  509.     (*Nr_iface->iftype->scan)(Nr_iface->hwaddr,argv[1]);
  510. #ifdef MAILBOX
  511.     setmbnrid();
  512. #endif
  513.     }
  514.     return 0;
  515. }
  516.  
  517. /* make an interface available to net/rom */
  518. /* arguments are:
  519.  * argv[0] - "interface"
  520.  * argv[1] - "iface" , the interface name
  521.  * argv[2] - "quality", the interface broadcast quality
  522.  * argv[3] - "n" or "v", to override the default (verbose)
  523.  *            n = never broadcast verbose
  524.  *            v = always broadcast verbose
  525.  */
  526. static
  527. int
  528. dointerface(argc,argv,p)
  529. int argc ;
  530. char *argv[] ;
  531. void *p;
  532. {
  533.     register struct iface *ifp ;
  534.     int i,mtu ;
  535.  
  536.     if(Nr_iface == NULLIF) {
  537.     tputs("Attach netrom interface first\n") ;
  538.         return 1 ;
  539.     }
  540.  
  541.     if(argc < 3) {
  542.     i = 0;
  543.     for(ifp=Ifaces;ifp;ifp=ifp->next) {
  544.         if(ifp->flags & IS_NR_IFACE){
  545.         if(!i) {
  546.             i = 1;
  547.             tputs("Iface  Qual Verbose\n");
  548.         }
  549.         tprintf("%-6s %-3d     %c\n",
  550.             ifp->name,ifp->quality,
  551.             (ifp->flags & NR_VERBOSE)?'Y':'N');
  552.         }
  553.     }
  554.     return 0;
  555.     }
  556.  
  557.     if((ifp = if_lookup(argv[1])) == NULLIF){
  558.     tprintf(Badinterface,argv[1]);
  559.         return 1;
  560.     }
  561.  
  562.     if(ifp->type != CL_AX25){
  563.         tprintf("Interface %s is not NETROM compatible\n",argv[1]);
  564.         return 1;
  565.     }
  566.  
  567.     /* activate the interface */
  568.     ifp->flags |= IS_NR_IFACE;
  569.  
  570.     /* set quality */
  571.     if((ifp->quality=atoi(argv[2])) > 255) /*Maximum quality possible*/
  572.     ifp->quality = 255;
  573.     /*check to see if quality is not 0 */
  574.     if(ifp->quality == 0)
  575.     ifp->quality = 1;
  576.  
  577.     /* default is none-verbose */
  578.     ifp->flags &= ~NR_VERBOSE;
  579.     if(argc > 3)
  580.     if(*argv[3] == 'v')
  581.         ifp->flags |= NR_VERBOSE;
  582.  
  583.     /* Check, and set the NETROM MTU - WG7J */
  584.     if((mtu = ifp->paclen - 20) < Nr_iface->mtu)
  585.         Nr_iface->mtu = mtu;
  586.  
  587.     /* Poll other nodes on this interface */
  588.     nr_bcpoll(ifp);
  589.  
  590.     return 0 ;
  591. }
  592.  
  593.     
  594. /* convert a null-terminated alias name to a blank-filled, upcased */
  595. /* version.  Return -1 on failure. */
  596. int
  597. putalias(to,from,complain)
  598. register char *to, *from ;
  599. int complain ;    
  600. {
  601.     int len, i ;
  602.     
  603.     if((len = strlen(from)) > ALEN) {
  604.         if(complain)
  605.             tprintf("alias too long - six characters max\n") ;
  606.         return -1 ;
  607.     }
  608.     
  609.     for(i = 0 ; i < ALEN ; i++) {
  610.         if(i < len) {
  611.             if(islower(*from))
  612.                 *to++ = toupper(*from++) ;
  613.             else
  614.                 *to++ = *from++ ;
  615.         }
  616.         else
  617.             *to++ = ' ' ;
  618.     }
  619.             
  620.     *to = '\0' ;
  621.     return 0 ;
  622. }
  623.  
  624. /* Add a route */
  625. static int
  626. dorouteadd(argc, argv,p)
  627. int argc ;
  628. char *argv[] ;
  629. void *p;
  630. {
  631.     char alias[AXALEN] ;
  632.     char dest[AXALEN] ;
  633.     unsigned quality ;
  634.     char neighbor[AXALEN] ;
  635.     struct iface *ifp;
  636.     int naddr ;
  637.  
  638.     /* format alias (putalias prints error message if necessary) */
  639.     if(putalias(alias,argv[1],1) == -1)
  640.         return -1 ;
  641.  
  642.     /* format destination callsign */
  643.     if(setcall(dest,argv[2]) == -1) {
  644.         tprintf("bad destination callsign\n") ;
  645.         return -1 ;
  646.     }
  647.  
  648.     /* find interface */
  649.     if((ifp = if_lookup(argv[3])) == NULLIF) {
  650.     tprintf(Badinterface,argv[3]);
  651.     return 1;
  652.     }
  653.  
  654.     /* Is it a netrom interface ? */
  655.     if(!(ifp->flags & IS_NR_IFACE)) {
  656.     tprintf(Badinterface,argv[3]) ;
  657.         return -1 ;
  658.     }
  659.     
  660.     /* get and check quality value */
  661.     if((quality = atoi(argv[4])) > 255) {
  662.         tprintf("maximum route quality is 255\n") ;
  663.         return -1 ;
  664.     }
  665.  
  666.     /* Change from 871225 -- no digis in net/rom table */
  667.     naddr = argc - 5 ;
  668.     if(naddr > 1) {
  669.         tprintf("Use the ax25 route command to specify digipeaters\n") ;
  670.         return -1 ;
  671.     }
  672.     
  673.     /* format neighbor address string */
  674.     setcall(neighbor,argv[5]) ;
  675.  
  676.     return nr_routeadd(alias,dest,ifp,quality,neighbor,1,0) ;
  677. }
  678.  
  679.  
  680. /* drop a route */
  681. static int
  682. doroutedrop(argc,argv,p)
  683. int argc ;
  684. char *argv[] ;
  685. void *p;
  686. {
  687.     char dest[AXALEN], neighbor[AXALEN] ;
  688.     struct iface *ifp;
  689.  
  690.     /* format destination and neighbor callsigns */
  691.     if(setcall(dest,argv[1]) == -1) {
  692.         tprintf("bad destination callsign\n") ;
  693.         return -1 ;
  694.     }
  695.     if(setcall(neighbor,argv[2]) == -1) {
  696.         tprintf("bad neighbor callsign\n") ;
  697.         return -1 ;
  698.     }
  699.  
  700.     /* find interface */
  701.     if((ifp = if_lookup(argv[3])) == NULLIF) {
  702.     tprintf(Badinterface,argv[3]);
  703.     return 1;
  704.     }
  705.  
  706.     /* Is it a netrom interface ? */
  707.     if(!(ifp->flags & IS_NR_IFACE)) {
  708.     tprintf(Badinterface,argv[3]) ;
  709.         return -1 ;
  710.     }
  711.     
  712.     return nr_routedrop(dest,neighbor,ifp) ;
  713. }
  714.  
  715. /* Broadcast nodes list on named interface. */
  716. static int
  717. dobcnodes(argc,argv,p)
  718. int argc ;
  719. char *argv[] ;
  720. void *p;
  721. {
  722.     struct iface *ifp;
  723.  
  724.     /* find interface */
  725.     if((ifp = if_lookup(argv[1])) == NULLIF) {
  726.     tprintf(Badinterface,argv[1]);
  727.     return 1;
  728.     }
  729.  
  730.     /* Is it a netrom interface ? */
  731.     if(!(ifp->flags & IS_NR_IFACE)) {
  732.     tprintf(Badinterface,argv[1]) ;
  733.         return -1 ;
  734.     }
  735.     nr_bcnodes(ifp) ;
  736.     return 0;
  737. }
  738.  
  739. /* Poll nodes for routes on named interface. - WG7J */
  740. static int
  741. dobcpoll(argc,argv,p)
  742. int argc ;
  743. char *argv[] ;
  744. void *p;
  745. {
  746.     struct iface *ifp;
  747.  
  748.     /* find interface */
  749.     if((ifp = if_lookup(argv[1])) == NULLIF) {
  750.     tprintf(Badinterface,argv[1]);
  751.     return 1;
  752.     }
  753.  
  754.     /* Is it a netrom interface ? */
  755.     if(!(ifp->flags & IS_NR_IFACE)) {
  756.     tprintf(Badinterface,argv[1]) ;
  757.         return -1 ;
  758.     }
  759.  
  760.     nr_bcpoll(ifp) ;
  761.     return 0;
  762. }
  763.  
  764. /* Set outbound node broadcast interval */
  765. static int
  766. donodetimer(argc,argv,p)
  767. int argc;
  768. char *argv[];
  769. void *p;
  770. {
  771.     if(argc < 2){
  772.         tprintf("Nodetimer %lu/%lu seconds\n",
  773.             read_timer(&Nodetimer)/1000L,
  774.             dur_timer(&Nodetimer)/1000L);
  775.         return 0;
  776.     }
  777.     stop_timer(&Nodetimer) ;        /* in case it's already running */
  778.     Nodetimer.func = (void (*)__ARGS((void*)))donodetick;/* what to call on timeout */
  779.     Nodetimer.arg = NULLCHAR;               /* dummy value */
  780.     set_timer(&Nodetimer,atoi(argv[1])*1000L);      /* set timer duration */
  781.     start_timer(&Nodetimer);                /* and fire it up */
  782.     return 0;
  783. }
  784.  
  785. void
  786. donodetick()
  787. {
  788.     struct iface *ifp;
  789.  
  790.     for(ifp=Ifaces;ifp;ifp=ifp->next)
  791.     if(ifp->flags & IS_NR_IFACE)
  792.         nr_bcnodes(ifp) ;
  793.  
  794.     /* Restart timer */
  795.     start_timer(&Nodetimer) ;
  796. }
  797.  
  798. /* Set timer for aging routes */
  799. static int
  800. doobsotimer(argc,argv,p)
  801. int argc;
  802. char *argv[];
  803. void *p;
  804. {
  805.     if(argc < 2){
  806.         tprintf("Obsotimer %lu/%lu seconds\n",
  807.             read_timer(&Obsotimer)/1000L,
  808.             dur_timer(&Obsotimer)/1000L);
  809.         return 0;
  810.     }
  811.     stop_timer(&Obsotimer) ;        /* just in case it's already running */
  812.     Obsotimer.func = (void (*)__ARGS((void*)))doobsotick;/* what to call on timeout */
  813.     Obsotimer.arg = NULLCHAR;               /* dummy value */
  814.     set_timer(&Obsotimer,atoi(argv[1])*1000L);      /* set timer duration */
  815.     start_timer(&Obsotimer);                /* and fire it up */
  816.     return 0;
  817. }
  818.  
  819.  
  820. /* Go through the routing table, reducing the obsolescence count of
  821.  * non-permanent routes, and purging them if the count reaches 0
  822.  */
  823. void
  824. doobsotick()
  825. {
  826.     register struct nrnbr_tab *np ;
  827.     register struct nrroute_tab *rp, *rpnext ;
  828.     register struct nr_bind *bp, *bpnext ;
  829.     int i ;
  830.  
  831.     for(i = 0 ; i < NRNUMCHAINS ; i++) {
  832.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  833.             rpnext = rp->next ;     /* save in case we free this route */
  834.         /* Check all bindings for this route */
  835.         for(bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  836.                 bpnext = bp->next ;     /* in case we free this binding */
  837.                 if(bp->flags & NRB_PERMANENT)   /* don't age these */
  838.                     continue ;
  839.                 if(--bp->obsocnt == 0) {                /* time's up! */
  840.                     if(bp->next != NULLNRBIND)
  841.                         bp->next->prev = bp->prev ;
  842.                     if(bp->prev != NULLNRBIND)
  843.                         bp->prev->next = bp->next ;
  844.                     else
  845.                         rp->routes = bp->next ;
  846.                     rp->num_routes-- ;                      /* one less binding */
  847.                     np = bp->via ;                          /* find the neighbor */
  848.                     free((char *)bp) ;                              /* now we can free the bind */
  849.                     /* Check to see if we can free the neighbor */
  850.                     if(--np->refcnt == 0) {
  851.                         if(np->next != NULLNTAB)
  852.                             np->next->prev = np->prev ;
  853.                         if(np->prev != NULLNTAB)
  854.                             np->prev->next = np->next ;
  855.                         else {
  856.                             Nrnbr_tab[nrhash(np->call)] = np->next ;
  857.                         }
  858.                         free((char *)np) ;      /* free the storage */
  859.                     }
  860.                 }
  861.             }
  862.             if(rp->num_routes == 0) {               /* did we free them all? */
  863.                 if(rp->next != NULLNRRTAB)
  864.                     rp->next->prev = rp->prev ;
  865.                 if(rp->prev != NULLNRRTAB)
  866.                     rp->prev->next = rp->next ;
  867.                 else
  868.                     Nrroute_tab[i] = rp->next ;
  869.         /* No more routes left !
  870.          * We should close/reset any netrom connections
  871.          * still idling for this route ! - WG7J
  872.          */
  873.         nrresetlinks(rp);
  874.                 free((char *)rp) ;
  875.             }
  876.         }
  877.     }
  878.  
  879.     start_timer(&Obsotimer) ;
  880. }
  881.  
  882.  
  883. static struct cmds Nfcmds[] = {
  884.     "add",  donfadd,        0, 3,
  885.         "netrom nodefilter add <neighbor> <interface> [quality]",
  886.     "drop", donfdrop,       0, 3,
  887.         "netrom nodefilter drop <neighbor> <interface>",
  888.     "mode", donfmode,       0, 0,   NULLCHAR,
  889.     NULLCHAR,       NULLFP((int,char**,void*)), 0, 0,
  890.         "nodefilter subcommands: add drop mode",
  891. } ;
  892.  
  893. /* nodefilter command multiplexer */
  894. static int
  895. donodefilter(argc,argv,p)
  896. int argc ;
  897. char *argv[] ;
  898. void *p;
  899. {
  900.     if(argc < 2) {
  901.         donfdump() ;
  902.         return 0 ;
  903.     }
  904.     return subcmd(Nfcmds,argc,argv,p) ;
  905. }
  906.  
  907. /* display a list of <callsign,interface> pairs from the filter
  908.  * list.
  909.  */
  910. static int
  911. donfdump()
  912. {
  913.     int i, column = 1 ;
  914.     struct nrnf_tab *fp ;
  915.     char buf[AXBUF] ;
  916.  
  917.     for(i = 0 ; i < NRNUMCHAINS ; i++)
  918.         for(fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  919.             pax25(buf,fp->neighbor) ;
  920.             tprintf("%-7s  %-8s  %-3d   ",
  921.          buf,fp->iface->name, fp->quality) ;
  922.             if(column++ == 3) {
  923.                 if(tprintf("\n") == EOF)
  924.                     return 0;
  925.                 column = 1 ;
  926.             }
  927.         }
  928.  
  929.     if(column != 1)
  930.         tprintf("\n") ;
  931.  
  932.     return 0 ;
  933. }
  934.  
  935. /* add an entry to the filter table */
  936. static int
  937. donfadd(argc,argv,p)
  938. int argc ;
  939. char *argv[] ;
  940. void *p;
  941. {
  942.     struct iface *ifp;
  943.     unsigned qual;
  944.     char neighbor[AXALEN] ;
  945.  
  946.     /* format callsign */
  947.     if(setcall(neighbor,argv[1]) == -1) {
  948.         tprintf("bad neighbor callsign\n") ;
  949.         return -1 ;
  950.     }
  951.  
  952.     /* find interface */
  953.     if((ifp = if_lookup(argv[2])) == NULLIF) {
  954.     tprintf(Badinterface,argv[2]);
  955.     return 1;
  956.     }
  957.  
  958.     /* Is it a netrom interface ? */
  959.     if(!(ifp->flags & IS_NR_IFACE)) {
  960.     tprintf(Badinterface,argv[2]) ;
  961.         return -1 ;
  962.     }
  963.  
  964.     qual = ifp->quality; /* set default quality */
  965.  
  966.     if(argc > 3)
  967.         qual = atoi(argv[3]);
  968.  
  969.     return nr_nfadd(neighbor,ifp,qual) ;
  970. }
  971.  
  972. /* drop an entry from the filter table */
  973. static int
  974. donfdrop(argc,argv,p)
  975. int argc ;
  976. char *argv[] ;
  977. void *p;
  978. {
  979.     struct iface *ifp;
  980.     char neighbor[AXALEN] ;
  981.  
  982.     /* format neighbor callsign */
  983.     if(setcall(neighbor,argv[1]) == -1) {
  984.         tprintf("bad neighbor callsign\n") ;
  985.         return -1 ;
  986.     }
  987.  
  988.     /* find interface */
  989.     if((ifp = if_lookup(argv[2])) == NULLIF) {
  990.     tprintf(Badinterface,argv[2]);
  991.     return 1;
  992.     }
  993.  
  994.     /* Is it a netrom interface ? */
  995.     if(!(ifp->flags & IS_NR_IFACE)) {
  996.     tprintf(Badinterface,argv[2]) ;
  997.         return -1 ;
  998.     }
  999.  
  1000.     return nr_nfdrop(neighbor,ifp) ;
  1001. }
  1002.  
  1003. /* nodefilter mode subcommand */
  1004. static int
  1005. donfmode(argc,argv,p)
  1006. int argc ;
  1007. char *argv[] ;
  1008. void *p;
  1009. {
  1010.     if(argc < 2) {
  1011.         tprintf("filter mode is ") ;
  1012.         switch(Nr_nfmode) {
  1013.             case NRNF_NOFILTER:
  1014.                 tprintf("none\n") ;
  1015.                 break ;
  1016.             case NRNF_ACCEPT:
  1017.                 tprintf("accept\n") ;
  1018.                 break ;
  1019.             case NRNF_REJECT:
  1020.                 tprintf("reject\n") ;
  1021.                 break ;
  1022.             default:
  1023.                 tprintf("some strange, unknown value\n") ;
  1024.         }
  1025.         return 0 ;
  1026.     }
  1027.     
  1028.     switch(argv[1][0]) {
  1029.         case 'n':
  1030.         case 'N':
  1031.             Nr_nfmode = NRNF_NOFILTER ;
  1032.             break ;
  1033.         case 'a':
  1034.         case 'A':
  1035.             Nr_nfmode = NRNF_ACCEPT ;
  1036.             break ;
  1037.         case 'r':
  1038.         case 'R':
  1039.             Nr_nfmode = NRNF_REJECT ;
  1040.             break ;
  1041.         default:
  1042.             tprintf("modes are: none accept reject\n") ;
  1043.             return -1 ;
  1044.     }
  1045.  
  1046.     return 0 ;
  1047. }
  1048.  
  1049. /* netrom network packet time-to-live initializer */
  1050. static int
  1051. donrttl(argc, argv,p)
  1052. int argc ;
  1053. char *argv[] ;
  1054. void *p;
  1055. {
  1056.     return setshort(&Nr_ttl,"Time to live",argc,argv);
  1057. }
  1058.  
  1059. /* show hidden (ie '#...') nodes or not */
  1060. static int
  1061. donrhidden(argc,argv,p)
  1062. int argc ;
  1063. char *argv[] ;
  1064. void *p;
  1065. {
  1066.     return setbool(&Nr_hidden,"Hidden nodes",argc,argv);
  1067. }
  1068.  
  1069. /* allow automatic derating of netrom routes on link failure */
  1070. static int
  1071. donrderate(argc,argv,p)
  1072. int argc ;
  1073. char *argv[] ;
  1074. void *p;
  1075. {
  1076.     extern int Nr_derate;
  1077.  
  1078.     return setbool(&Nr_derate,"Derate flag",argc,argv);
  1079. }
  1080.  
  1081. /* promiscuous acceptance of broadcasts */
  1082. static int
  1083. donrpromisc(argc,argv,p)
  1084. int argc ;
  1085. char *argv[] ;
  1086. void *p;
  1087. {
  1088.     extern int Nr_promisc;
  1089.  
  1090.     return setbool(&Nr_promisc,"Promiscuous flag",argc,argv);
  1091. }
  1092.  
  1093. #ifdef ALLSESSIONS
  1094. /* Initiate a NET/ROM transport connection */
  1095. static int
  1096. donrconnect(argc,argv,p)
  1097. int argc ;
  1098. char *argv[] ;
  1099. void *p;
  1100. {
  1101.     struct nrroute_tab *np;
  1102.     struct sockaddr_nr lsocket, fsocket;
  1103.     char alias[AXBUF];
  1104.     struct session *sp;
  1105.     int split = 0;
  1106.  
  1107.     /*Make sure this comes from console - WG7J*/
  1108.     if(Curproc->input != Command->input)
  1109.         return 0;
  1110.  
  1111. #ifdef ALLSERV
  1112.     if(argv[0][0] == 's')
  1113.     split  = 1;
  1114. #endif
  1115.  
  1116.     /* Get a session descriptor */
  1117.     if((sp = newsession(argv[1],NRSESSION,split)) == NULLSESSION) {
  1118.     tputs(TooManySessions);
  1119.         return 1 ;
  1120.     }
  1121.  
  1122.     if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  1123.     tputs(Nosock);
  1124.         keywait(NULLCHAR,1);
  1125.         freesession(sp);
  1126.         return 1;
  1127.     }
  1128.  
  1129.     /* See if the requested destination is a known alias or call,
  1130.      * use it if it is.  Otherwize give an error message. - WG7J
  1131.      */
  1132.     putalias(alias,argv[1],0);
  1133.     strupr(argv[1]);    /*make sure it's upper case*/
  1134.     if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  1135.     /*no such call or node alias*/
  1136.     tputs("no such node\n\n");
  1137.     keywait(NULLCHAR,1);
  1138.         freesession(sp);
  1139.         return 1;
  1140.     }
  1141.  
  1142.     /* Setup the local side of the connection */
  1143.     lsocket.nr_family = AF_NETROM;
  1144.  
  1145.     /* Set up our local username, bind would use Mycall instead */
  1146.     memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
  1147.  
  1148.     /* Putting anything else than Nr_iface->hwaddr here will not work ! */
  1149.     memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
  1150.  
  1151.     /* Now bind the socket to this */
  1152.     bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  1153.  
  1154.     
  1155.     /* Set up the remote side of the connection */
  1156.     fsocket.nr_family = AF_NETROM;
  1157.     memcpy(fsocket.nr_addr.user,np->call,AXALEN);
  1158.     memcpy(fsocket.nr_addr.node,np->call,AXALEN);
  1159.     fsocket.nr_family = AF_NETROM;
  1160.  
  1161.     return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr));
  1162. }
  1163. #endif
  1164.  
  1165. /* Reset a net/rom connection abruptly */
  1166. static int
  1167. donrreset(argc,argv,p)
  1168. int argc;
  1169. char *argv[];
  1170. void *p;
  1171. {
  1172.     struct nr4cb *cb ;
  1173.  
  1174.     cb = MK_FP(htoi(argv[1]),8);
  1175.     if(!nr4valcb(cb)){
  1176.         tprintf(Notval);
  1177.         return 1;
  1178.     }
  1179.     reset_nr4(cb);
  1180.     return 0;
  1181. }
  1182.  
  1183. /* Force retransmission on a net/rom connection */
  1184.  
  1185. static int
  1186. donrkick(argc,argv,p)
  1187. int argc;
  1188. char *argv[];
  1189. void *p;
  1190. {
  1191.     struct nr4cb *cb ;
  1192.  
  1193.     cb = MK_FP(htoi(argv[1]),8);
  1194.     if(kick_nr4(cb) == -1) {
  1195.         tprintf(Notval);
  1196.         return 1;
  1197.     } else
  1198.         return 0;
  1199. }
  1200.  
  1201. /* netrom transport ACK delay timer */
  1202. static int
  1203. donracktime(argc, argv,p)
  1204. int argc ;
  1205. char *argv[] ;
  1206. void *p;
  1207. {
  1208.     return setlong(&Nr4acktime,"Ack delay time (ms)",argc,argv);
  1209. }
  1210.  
  1211. /* netrom transport choke timeout */
  1212. static int
  1213. donrchoketime(argc, argv,p)
  1214. int argc ;
  1215. char *argv[] ;
  1216. void *p;
  1217. {
  1218.     return setlong(&Nr4choketime,"Choke timeout (ms)",argc,argv);
  1219. }
  1220.  
  1221. /* netrom transport initial round trip time */
  1222.  
  1223. static int
  1224. donrirtt(argc, argv,p)
  1225. int argc ;
  1226. char *argv[] ;
  1227. void *p;
  1228. {
  1229.     return setlong(&Nr4irtt,"Initial RTT (ms)",argc,argv);
  1230. }
  1231.  
  1232. /* netrom transport receive queue length limit.  This is the */
  1233. /* threshhold at which we will CHOKE the sender. */
  1234.  
  1235. static int
  1236. donrqlimit(argc, argv,p)
  1237. int argc ;
  1238. char *argv[] ;
  1239. void *p;
  1240. {
  1241.     return setshort(&Nr4qlimit,"Queue limit (bytes)",argc,argv);
  1242. }
  1243.  
  1244. /* Display or change our NET/ROM username */
  1245. static int
  1246. donruser(argc,argv,p)
  1247. int argc;
  1248. char *argv[];
  1249. void *p;
  1250. {
  1251.     char buf[AXBUF];
  1252.  
  1253.     if(argc < 2){
  1254.         pax25(buf,Nr4user);
  1255.         tprintf("%s\n",buf);
  1256.         return 0;
  1257.     }
  1258.     if(setcall(Nr4user,argv[1]) == -1)
  1259.         return -1;
  1260.     Nr4user[ALEN] |= E;
  1261.     return 0;
  1262. }
  1263.  
  1264. /* netrom transport maximum window.  This is the largest send and */
  1265. /* receive window we may negotiate */
  1266.  
  1267. static int
  1268. donrwindow(argc, argv,p)
  1269. int argc ;
  1270. char *argv[] ;
  1271. void *p;
  1272. {
  1273.     return setshort(&Nr4window,"Window (frames)",argc,argv);
  1274. }
  1275.  
  1276. /* netrom transport maximum retries.  This is used in connect and */
  1277. /* disconnect attempts; I haven't decided what to do about actual */
  1278. /* data retries yet. */
  1279.  
  1280. static int
  1281. donrretries(argc, argv,p)
  1282. int argc ;
  1283. char *argv[] ;
  1284. void *p;
  1285. {
  1286.     return setshort(&Nr4retries,"Retry limit",argc,argv);
  1287. }
  1288.  
  1289.  
  1290. /* Display the status of NET/ROM connections */
  1291.  
  1292. static int
  1293. donrstatus(argc, argv,p)
  1294. int argc ;
  1295. char *argv[] ;
  1296. void *p;
  1297. {
  1298.     int i ;
  1299.     struct nr4cb *cb ;
  1300.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  1301.     
  1302.     if(argc < 2) {
  1303. #ifdef UNIX
  1304.         tprintf("&NCB     Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1305. #else
  1306.     tprintf("&NCB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1307. #endif
  1308.         for(i = 0 ; i < NR4MAXCIRC ; i++) {
  1309.             if((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1310.                 continue ;
  1311.             pax25(luser,cb->local.user) ;
  1312.             pax25(ruser,cb->remote.user) ;
  1313.             pax25(node,cb->remote.node) ;
  1314. #ifdef UNIX
  1315.             if(tprintf("%8.8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  1316. #else
  1317.         if(tprintf("%4.4x   %3d %5d %5d %9s  %9s %-9s %s\n",
  1318. #endif
  1319.          FP_SEG(cb), cb->nbuffered, len_q(cb->txq),
  1320.              len_p(cb->rxq), luser, ruser, node,
  1321.              Nr4states[cb->state]) == EOF)
  1322.                 break;
  1323.         }
  1324.         return 0 ;
  1325.     }
  1326.     cb = MK_FP(htoi(argv[1]),8);
  1327.     if(!nr4valcb(cb)) {
  1328.         tprintf(Notval) ;
  1329.         return 1 ;
  1330.     }
  1331.     donrdump(cb) ;
  1332.     return 0 ;
  1333. }
  1334.  
  1335. /* Dump one control block */
  1336.  
  1337. void
  1338. donrdump(cb)
  1339. struct nr4cb *cb ;
  1340. {
  1341.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  1342.     unsigned seq ;
  1343.     struct nr4txbuf *b ;
  1344.     struct timer *t ;
  1345.  
  1346.     pax25(luser,cb->local.user) ;
  1347.     pax25(ruser,cb->remote.user) ;
  1348.     pax25(node,cb->remote.node) ;
  1349.  
  1350.     tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1351.            luser, cb->mynum, cb->myid, ruser, node,
  1352.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1353.  
  1354.     tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1355.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1356.            len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1357.  
  1358.     tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1359.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1360.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1361.  
  1362.     tprintf("TACK: ") ;
  1363.     if(run_timer(&cb->tack))
  1364.         tprintf("%lu", read_timer(&cb->tack)) ;
  1365.     else
  1366.         tprintf("stop") ;
  1367.     tprintf("/%lu ms; ", dur_timer(&cb->tack)) ;
  1368.  
  1369.     tprintf("TChoke: ") ;
  1370.     if(run_timer(&cb->tchoke))
  1371.         tprintf("%lu", read_timer(&cb->tchoke)) ;
  1372.     else
  1373.         tprintf("stop") ;
  1374.     tprintf("/%lu ms; ", dur_timer(&cb->tchoke)) ;
  1375.  
  1376.     tprintf("TCD: ") ;
  1377.     if(run_timer(&cb->tcd))
  1378.         tprintf("%lu", read_timer(&cb->tcd)) ;
  1379.     else
  1380. #ifndef NR4TDISC
  1381.     tprintf("stop") ;
  1382.     tprintf("/%lu ms", dur_timer(&cb->tcd)) ;
  1383. #else
  1384.     tprintf("stop") ;
  1385.     tprintf("/%lu ms; ", dur_timer(&cb->tcd)) ;
  1386.  
  1387.     tprintf("TDisc: ") ;
  1388.     if(run_timer(&cb->tdisc))
  1389.     tprintf("%lu", (read_timer(&cb->tdisc)/1000L)) ;
  1390.     else
  1391.         tprintf("stop") ;
  1392.     tprintf("/%lu", (dur_timer(&cb->tdisc)/1000L)) ;
  1393. #endif
  1394.  
  1395.     if(run_timer(&cb->tcd))
  1396.         tprintf("; Tries: %u\n", cb->cdtries) ;
  1397.     else
  1398.     tputc('\n') ;
  1399.  
  1400.     tprintf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1401.            cb->blevel, cb->srtt, cb->mdev) ;
  1402.  
  1403.     /* If we are connected and the send window is open, display */
  1404.     /* the status of all the buffers and their timers */
  1405.     
  1406.     if(cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1407.  
  1408.         tprintf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1409.  
  1410.         for(seq = cb->ackxpected ;
  1411.              nr4between((unsigned)cb->ackxpected, seq, (unsigned)cb->nextosend) ;
  1412.              seq = (seq + 1) & NR4SEQMASK) {
  1413.  
  1414.             b = &cb->txbufs[seq % cb->window] ;
  1415.             t = &b->tretry ;
  1416.  
  1417.             if(tprintf("            %3u   %3d  %5d  %lu/%lu\n",
  1418.              seq, len_p(b->data), b->retries + 1,
  1419.              read_timer(t), dur_timer(t))
  1420.              == EOF)
  1421.                 break;
  1422.         }
  1423.  
  1424.     }
  1425.  
  1426. }
  1427.  
  1428. /* netrom timers type - linear v exponential */
  1429. static int
  1430. donrtype(argc,argv,p)
  1431. int argc ;
  1432. char *argv[] ;
  1433. void *p ;
  1434. {
  1435.     extern unsigned Nr_timertype;
  1436.  
  1437.     if(argc < 2) {
  1438.         tprintf("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential" ) ;
  1439.         return 0 ;
  1440.     }
  1441.     
  1442.     switch(argv[1][0]) {
  1443.         case 'l':
  1444.         case 'L':
  1445.             Nr_timertype = 1 ;
  1446.             break ;
  1447.         case 'e':
  1448.         case 'E':
  1449.             Nr_timertype = 0 ;
  1450.             break ;
  1451.         default:
  1452.             tprintf("use: netrom timertype [linear|exponential]\n") ;
  1453.             return -1 ;
  1454.     }
  1455.  
  1456.     return 0 ;
  1457. }
  1458.  
  1459. static int
  1460. dominquality(argc,argv,p)
  1461. int argc ;
  1462. char *argv[] ;
  1463. void *p ;
  1464. {
  1465.     unsigned val ;
  1466.     extern unsigned Nr_autofloor;
  1467.  
  1468.     if(argc < 2) {
  1469.         tprintf("%u\n", Nr_autofloor) ;
  1470.         return 0 ;
  1471.     }
  1472.  
  1473.     val = atoi(argv[1]) ;
  1474.  
  1475.     if(val == 0 || val > 255 ) {
  1476.         tprintf("The minimum acceptable quality must be 1 to 255\n") ;
  1477.         return 1 ;
  1478.     }
  1479.     
  1480.     Nr_autofloor = val ;
  1481.  
  1482.     return 0 ;
  1483. }
  1484.  
  1485. /* Fixed and now functional, 920317 WG7J */
  1486. int
  1487. donrload(argc,argv,p)
  1488. int argc ;
  1489. char *argv[] ;
  1490. void *p;
  1491. {
  1492.     char buff[255];
  1493.     FILE *fn;
  1494.     time_t now, prev;
  1495. #ifdef notdef
  1496.     long t1,t2;
  1497.     int j;
  1498. #endif
  1499.     int quality,obso;
  1500.     int permanent,record;
  1501.     struct iface *ifp;
  1502.     char alias[12],dest[12],iface[12],neighbor[12],type[3],*ptr;
  1503.     char destalias[ALEN+1]; /*alias in 'alias form'*/
  1504.     char destcall[AXALEN];  /*in callsign (ie shifted) form */
  1505.     char destneighbor[AXALEN];
  1506.  
  1507.     if(Nr_iface == NULLIF) {
  1508.     tputs("Attach netrom interface first\n") ;
  1509.     return 1;
  1510.     }
  1511.  
  1512.     if((fn = fopen(Netromfile,READ_TEXT)) == NULLFILE){
  1513. /*
  1514.     tputs("Can't open netrom save file!\n");
  1515. */
  1516.     return 1;
  1517.     }
  1518.  
  1519.     if(fgets(buff,sizeof(buff),fn) == NULLCHAR){ /* read the timestamp */
  1520.         fclose(fn);
  1521.         return 1;
  1522.     }
  1523.     if((strncmp(buff,"time = ",7))!= 0){
  1524. /*
  1525.     tputs("Wrong node file content\n");
  1526. */
  1527.     fclose(fn);
  1528.         return 1;
  1529.     }
  1530.     time(&now);
  1531.     sscanf(buff,"time =%ld",&prev);
  1532. /*
  1533.     tprintf("now = %ld , prev = %ld\n",now,prev);
  1534. */
  1535.     if(prev >= now){
  1536.     /*
  1537.     tputs("You traveled back in time!!\n");
  1538.     */
  1539.     fclose(fn);
  1540.         return 1;
  1541.     }
  1542. #ifdef notdef
  1543.     t1 = now - prev;
  1544.     t2 = dur_timer(&Obsotimer)/1000L;
  1545.     j = t1 / t2;            /* recalculate obsolete count */
  1546.     tprintf("%ld seconds are past ( %d obsolete scans)\n",t1,j);
  1547. #endif
  1548.  
  1549.     while(fgets(buff,sizeof(buff),fn) != NULLCHAR){
  1550.         if((ptr = strchr(buff,':')) == 0){
  1551.             sscanf(buff,"%s%s%i%i%s%s"
  1552.                 ,dest,type,&quality,&obso,iface,neighbor);
  1553.             alias[0] = '\0';
  1554.         } else {        
  1555.             *ptr = ' ';
  1556.             sscanf(buff,"%s%s%s%i%i%s%s"
  1557.                 ,alias,dest,type,&quality,&obso,iface,neighbor);
  1558.         }
  1559.     /*Set and check calls / alias - WG7J */
  1560.     if(setcall(destcall,dest) == -1) {
  1561.         /*
  1562.         tprintf("Bad call %s\n",dest);
  1563.         */
  1564.         continue;
  1565.     }
  1566.     if(setcall(destneighbor,neighbor) == -1) {
  1567.         /*
  1568.         tprintf("Bad call %s\n",neighbor);
  1569.         */
  1570.         continue;
  1571.     }
  1572.     if(putalias(destalias,alias,1) == -1)
  1573.         continue;
  1574.  
  1575.     /* find interface */
  1576.     if((ifp = if_lookup(iface)) == NULLIF)
  1577.         continue;
  1578.  
  1579.     /* Is it a netrom interface ? */
  1580.     if(!(ifp->flags & IS_NR_IFACE))
  1581.         continue;
  1582.  
  1583.         /* get and check quality value */
  1584.     if(quality  > 255 || quality < Nr_autofloor) {
  1585.         /*
  1586.             tprintf("maximum route quality is 255\n") ;
  1587.          */
  1588.          continue;
  1589.     }
  1590.     /* Check the type of route - WG7J */
  1591.     permanent = record = 0;
  1592.     if(strchr(type,'P') != NULLCHAR)
  1593.         permanent = 1;
  1594.     else {
  1595.         if(strchr(type,'R') != NULLCHAR)
  1596.         record = 1;
  1597.     }
  1598.     nr_routeadd(destalias,destcall,ifp,(unsigned)quality,destneighbor, \
  1599.             (unsigned)permanent,(unsigned)record) ;
  1600.     }
  1601.     fclose(fn);
  1602.     return 0;
  1603. }
  1604.  
  1605. int
  1606. donrsave(argc,argv,p)
  1607. int argc ;
  1608. char *argv[] ;
  1609. void *p;
  1610. {
  1611.     register struct nrroute_tab *rp ;
  1612.     register struct nr_bind *bp ;
  1613.     register struct nrnbr_tab *np ;
  1614.     char neighbor[AXBUF] ;
  1615.     register int i;
  1616.     char buf[16] ;
  1617.     char *cp ;
  1618.     FILE *fn;
  1619.     time_t now;
  1620.     
  1621. #ifdef __TURBOC__
  1622.     if((fn = fopen(Netromfile,"wt+")) == NULLFILE){
  1623. #else
  1624.     if((fn = fopen(Netromfile,"w+")) == NULLFILE){
  1625. #endif
  1626.     tputs("Can't write netrom save file!\n");
  1627.         return 1;
  1628.     }
  1629.     time(&now);
  1630.     fprintf(fn,"time = %ld\n",now);
  1631.     for(i = 0 ; i < NRNUMCHAINS ; i++){
  1632.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
  1633.             strcpy(buf,rp->alias) ;
  1634.             /* remove trailing spaces */
  1635.             if((cp = strchr(buf,' ')) == NULLCHAR)
  1636.                 cp = &buf[strlen(buf)] ;
  1637.             if(cp != buf)           /* don't include colon for null alias */
  1638.                 *cp++ = ':' ;
  1639.             for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1640.                 pax25(cp,rp->call) ;
  1641.                 fprintf(fn,"%-16s  ",buf) ;
  1642.                 np = bp->via ;
  1643.                 if(fprintf(fn,"%1s %3d  %3d  %-8s  %s\n",
  1644.               (bp->flags & NRB_PERMANENT ? "P" :
  1645.                       bp->flags & NRB_RECORDED ? "R" : "X"),
  1646.               bp->quality,bp->obsocnt,
  1647.               np->iface->name,
  1648.                       pax25(neighbor,np->call)) == EOF)
  1649.                    break;
  1650.             }
  1651.         }
  1652.     }
  1653.     fclose(fn);
  1654.     return 0;
  1655. }
  1656.